package interceptcrossing;

/**
 * Абсцисса граничной точки отрезка. Содержит значение абсциссы, информацию
 * об отрезке, границей которого является и тип границы - левая или правая
 *
 * @author Igor Botyan
 */
public class Abscissa implements Comparable<Abscissa> {

	/**
	 * Значение координаты по оси абсцисс
	 */
	public final double x;

	/**
	 * Вид границы - левая или правая
	 */
	public final Bound bound;

	/**
	 * Отрезок, к которому принадлежит точка с заданной абсциссей
	 */
	public final Intercept intercept;

	public final Intercept secondIntercept;

	/**
	 * Создание новой абсциссы
	 *
	 * @param intercept отрезок, абсцисса которого будет взята
	 * @param bound     какой границе принадлежит заданная точка - левой или правой
	 */
	public Abscissa(Intercept intercept, Bound bound, Intercept secondIntercept) {
		assert (intercept != null);

		this.bound = bound;
		this.intercept = intercept;
		this.secondIntercept = secondIntercept;

		switch (bound) {
			case LEFT:
				this.x = intercept.begin().x();
				break;
			case RIGHT:
				this.x = intercept.end().x();
				break;
			case INTERSECTION:
				//TODO if (secondIntercept != null)
				this.x = intercept.intersects(secondIntercept).x();
				break;
			default:
				this.x = 0;
		}
	}

	@Override
	public boolean equals(Object obj) {
		boolean ret = false;

		if (obj instanceof Abscissa) {
			Abscissa a = (Abscissa) obj;

			return (this.x == a.x) && (this.bound.equals(a.bound)) &&
				(this.intercept.equals(a.intercept));
		}

		return ret;
	}

	@Override
	public int hashCode() {
		int hash = 7;
		hash = 71 * hash + (int) (Double.doubleToLongBits(this.x)
			^ (Double.doubleToLongBits(this.x) >>> 32));
		hash = 71 * hash + (this.bound != null ? this.bound.hashCode() : 0);
		hash = 71 * hash + (this.intercept != null
			? this.intercept.hashCode() : 0);
		return hash;
	}

	public int compareTo(Abscissa o) {
		int ret = Double.compare(this.x, o.x);

		if (ret == 0) {
			ret = this.compareByBounds(o);

			if (ret == 0) {
				ret = this.compareByOrdinates(o);
			}
		}

		return ret;
	}

	private int compareByBounds(Abscissa o) {
		int ret;

		if (this.bound.equals(Bound.LEFT)) {
			ret = (o.bound.equals(Bound.RIGHT)) ? -1 : 0;
		} else {
			ret = (o.bound.equals(Bound.LEFT)) ? 1 : 0;
		}

		return ret;
	}

	private int compareByOrdinates(Abscissa o) {
		int ret;

		if (this.bound.equals(Bound.LEFT)) {
			ret = Double.compare(this.intercept.begin().y(),
				o.intercept.begin().y());
		} else {
			ret = Double.compare(this.intercept.end().y(),
				o.intercept.end().y());
		}

		return ret;
	}
}
